package com.sakiko.audiobook.album.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sakiko.audiobook.album.mapper.AlbumInfoMapper;
import com.sakiko.audiobook.album.mapper.TrackInfoMapper;
import com.sakiko.audiobook.album.mapper.TrackStatMapper;
import com.sakiko.audiobook.album.service.TrackInfoService;
import com.sakiko.audiobook.album.service.VodService;
import com.sakiko.audiobook.common.constant.SystemConstant;
import com.sakiko.audiobook.common.result.Result;
import com.sakiko.audiobook.model.album.AlbumInfo;
import com.sakiko.audiobook.model.album.TrackInfo;
import com.sakiko.audiobook.model.album.TrackStat;
import com.sakiko.audiobook.query.album.TrackInfoQuery;
import com.sakiko.audiobook.user.client.UserInfoFeignClient;
import com.sakiko.audiobook.vo.album.*;
import com.sakiko.audiobook.vo.user.UserInfoVo;
import jakarta.validation.constraints.AssertTrue;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class TrackInfoServiceImpl extends ServiceImpl<TrackInfoMapper, TrackInfo> implements TrackInfoService {

    @Autowired
    private TrackInfoMapper trackInfoMapper;

    @Autowired
    private AlbumInfoMapper albumInfoMapper;

    @Autowired
    private VodService vodService;

    @Autowired
    private TrackStatMapper trackStatMapper;

    @Autowired
    private UserInfoFeignClient userInfoFeignClient;

    /**
     * 保存声音
     *
     * @param trackInfoVo
     * @param userId
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveTrackInfo(TrackInfoVo trackInfoVo, Long userId) {
        // todo: track_info
        TrackInfo trackInfo = new TrackInfo();
        // 赋值属性
        // 提交属性 albumId coverUrl isOpen mediaFileId mediaUrl trackIntro trackTitle
        BeanUtils.copyProperties(trackInfoVo, trackInfo);
        // userId
        trackInfo.setUserId(userId);
        // order_num ==> 声音的序号 order_num = include_track_count + 1;
        // select include_track_count from album_info where id = ?
        AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfoVo.getAlbumId());
        if (null != albumInfo)
            trackInfo.setOrderNum(albumInfo.getIncludeTrackCount() + 1);
        // 流媒体相关 media_duration media_file_id media_url media_size media_type
        TrackMediaInfoVo trackMediaInfoVo = vodService.getMediaInfo(trackInfoVo.getMediaFileId());
        // 给声音对象赋值
        trackInfo.setMediaUrl(trackMediaInfoVo.getMediaUrl());
        trackInfo.setMediaDuration(trackMediaInfoVo.getDuration());
        trackInfo.setMediaType(trackMediaInfoVo.getType());
        trackInfo.setMediaSize(trackMediaInfoVo.getSize());
        // 保存声音对象
        trackInfoMapper.insert(trackInfo);
        // todo: track_stat
        // 保存声音统计数据
        this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_PLAY);
        this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_COLLECT);
        this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_PRAISE);
        this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_COMMENT);
        // todo: album_info
        // 更新专辑包含声音总数
        albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount() + 1);
        this.albumInfoMapper.updateById(albumInfo);
    }

    /**
     * 分页查询用户声音列表
     *
     * @param trackListVoPage
     * @param trackInfoQuery
     * @return
     */
    @Override
    public IPage<TrackListVo> findUserTrackPage(Page<TrackListVo> trackListVoPage, TrackInfoQuery trackInfoQuery) {
        // 需要的数据包含: 声音的标题，图片... track_info; 声音的统计信息(track_stat)
        return trackInfoMapper.selectUserTrackPage(trackListVoPage, trackInfoQuery);
    }

    /**
     * 根据声音 Id删除声音对象
     *
     * @param trackId
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeTrackInfo(Long trackId) {
        // todo: track_info
        TrackInfo trackInfo = this.getById(trackId);
        if (null == trackInfo)
            throw new RuntimeException("选中删除声音对象不存在");
        this.trackInfoMapper.deleteById(trackId);
        // todo: track_stat
        trackStatMapper.delete(new LambdaQueryWrapper<TrackStat>().eq(TrackStat::getTrackId, trackId));
        // todo: album_info
        AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfo.getAlbumId());
        // 赋值包含声音总数
        albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount() - 1);
        this.albumInfoMapper.updateById(albumInfo);
        // 维护当前声音编号 order_num: update track_info set order_num = order_num -1 where album_id = ? and order_num > ? and is_deleted = 0;
        trackInfoMapper.updateOrderNum(trackInfo.getAlbumId(), trackInfo.getOrderNum());
        // todo: vodService 云点播
        vodService.delMediaInfo(trackInfo.getMediaFileId());
    }

    /**
     * 根据声音 id获取声音对象
     *
     * @param trackId
     * @return
     */
    @Override
    public TrackInfo getTrackInfo(long trackId) {
        return trackInfoMapper.selectById(trackId);
    }

    /**
     * 修改声音
     *
     * @param trackId
     * @param trackInfoVo
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateTrackInfo(Long trackId, TrackInfoVo trackInfoVo) {
        // track_info
        TrackInfo trackInfo = this.getById(trackId);
        // 赋值 [包括新的 mediaFileId 赋值
        BeanUtils.copyProperties(trackInfoVo, trackInfo);
        // 声音到底是否修改了？根据流媒体 Id,判断声音是否修改了
        if (!trackInfo.getMediaFileId().equals(trackInfoVo.getMediaFileId())) {
            // 声音被修改了
            // 重[新]获取流媒体最新数据
            TrackMediaInfoVo trackMediaInfoVo = vodService.getMediaInfo(trackInfoVo.getMediaFileId());
            trackInfo.setMediaType(trackMediaInfoVo.getType());
            trackInfo.setMediaSize(trackMediaInfoVo.getSize());
            trackInfo.setMediaUrl(trackMediaInfoVo.getMediaUrl());
            trackInfo.setMediaDuration(trackMediaInfoVo.getDuration());
            // 删除 [原有] 声音
            vodService.delMediaInfo(trackInfo.getMediaFileId());
        }
        // 修改声音对象
        this.updateById(trackInfo);
        // 生产环境下可以将更新后的收藏什么的track_stat清空，但是反正是模拟数据，这里不清空，好看点
    }

    @Override
    public IPage<AlbumTrackListVo> findAlbumTrackPage(Page<AlbumTrackListVo> trackListVoPage, Long albumId, Long userId) {
        // 1、先根据专辑 Id与分页条件，查询出声音列表数据
        IPage<AlbumTrackListVo> iPage = trackInfoMapper.selectAlbumTrackPage(trackListVoPage, albumId);
        // 2、判断当前用户是否登录
        // 获取对应专辑
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        if (null == userId) {
            // 未登录，专辑类型除免费之外。剔除免费试听的声音之外，都需要付费！
            if (!SystemConstant.ALBUM_PAY_TYPE_FREE.equals(albumInfo.getPayType())) { // 只要不是免费的
                // 设置付费声音列表; select tracks_for_free from album_info where id = 303; tracks_for_free: 标识免费的试听集数
                iPage.getRecords().stream().filter(albumTrackListVo -> albumTrackListVo.getOrderNum() > albumInfo.getTracksForFree()).forEach(albumTrackListVo -> albumTrackListVo.setIsShowPaidMark(true));
            }
        } else {
            boolean isNeedPaidMark = false;
            // 用户已经登陆
            if (SystemConstant.ALBUM_PAY_TYPE_VIPFREE.equals(albumInfo.getPayType())) { // vip免费
                // 判断用户是否是 vip & 是否过期
                Result<UserInfoVo> userInfoVoResult = userInfoFeignClient.getUserInfo(userId);
                Assert.notNull(userInfoVoResult, "用户信息结果集不存在！");
                UserInfoVo userInfoVo = userInfoVoResult.getData();
                Assert.notNull(userInfoVo, "用户信息不存在！");
                if (0 == userInfoVo.getIsVip() || (1 == userInfoVo.getIsVip() && userInfoVo.getVipExpireTime().before(new Date()))) { // 过期时间在当前系统时间之前
                    isNeedPaidMark = true;
                }
            } else if (SystemConstant.ALBUM_PAY_TYPE_REQUIRE.equals(albumInfo.getPayType())) { // 付费
                isNeedPaidMark = true;
            } // 免费的默认设置成了 false
            // 同一处理付费情况 (vip过期或需要付费情况)
            if (isNeedPaidMark) {
                // 付费; 除去试听、用户购买过的(专辑、声音)
                List<AlbumTrackListVo> albumTrackWhichNeedPay = iPage.getRecords().stream().filter(albumTrackListVo -> albumTrackListVo.getOrderNum() > albumInfo.getTracksForFree()).collect(Collectors.toList());
                // 远程调用 获取用户是否购买过专辑或声音 Id
                // 购买的是专辑装所搜的声音 map.put(trackId, 1) || 购买的是声音 买了 map.put(trackId, 1)，没买 map.put(trackId, 0)
                List<Long> trackIdList = albumTrackWhichNeedPay.stream().map(AlbumTrackListVo::getTrackId).collect(Collectors.toList());
                // 传递专辑 Id，声音 Id集合
                Result<Map<Long, Integer>> mapResult = userInfoFeignClient.userIsPaidTrack(albumId, trackIdList); // 可以在 user微服务中获取用户 Id
                Assert.notNull(mapResult, "TrackInfoServiceImpl.findAlbumTrackPage远程调用失败");
                Map<Long, Integer> map = mapResult.getData();
                albumTrackWhichNeedPay.forEach(albumTrackListVo -> albumTrackListVo.setIsShowPaidMark(0 == map.get(albumTrackListVo.getTrackId()))); // albumTrackWhichNeedPay是 Collectors.toList()出来的不会是空的，最多是不做处理
            }
        }
        // 返回数据
        return iPage;
    }

    @Override
    @Transactional
    public void trackStatUpdate(TrackStatMqVo trackStatMqVo) {
        // 先更新声音的播放量
        // update track_stat set stat_num = stat_num + ? where track_id = ? and stat_type = ? and is_deleted = 0;
        trackStatMapper.trackStatUpdate(trackStatMqVo.getCount(), trackStatMqVo.getTrackId(), trackStatMqVo.getStatType());
        // 需要更新专辑的播放量
        if (SystemConstant.TRACK_STAT_PLAY.equals(trackStatMqVo.getStatType())) {
            albumInfoMapper.albumStatUpdate(trackStatMqVo.getCount(), trackStatMqVo.getAlbumId(), SystemConstant.ALBUM_STAT_PLAY);
        }

    }

    @Override
    public List<Map<String, Object>> findUserTrackPaidList(Long trackId) {
        // 先查询相关信息
        TrackInfo trackInfo = this.getById(trackId);
        AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfo.getAlbumId());
        BigDecimal price = albumInfo.getPrice(); // 单条声音价格
        // 当前声音专辑的所有付费声音列表 select * from track_info where order_num > ? and album_id = ? and is_deleted = 0
        List<TrackInfo> trackInfoList = trackInfoMapper.selectList(new LambdaQueryWrapper<TrackInfo>()
                .eq(TrackInfo::getAlbumId, albumInfo.getId())
                .eq(TrackInfo::getIsDeleted, 0)
                .gt(TrackInfo::getOrderNum, albumInfo.getTracksForFree())); // > free 而不是 > 当前声音，买的不应该显示 “后”，得看后面拿到 trackCount的逻辑
        // 用户已经购买的声音列表
        Result<List<Long>> userPaidTrackList = userInfoFeignClient.findUserPaidTrackList(albumInfo.getId());
        Assert.notNull(userPaidTrackList, "用户已经购买的声音列表结果集为空！");
        List<Long> paidTrackList = userPaidTrackList.getData();
        // 用户需要付费的列表
        List<Long> trackInfoAllList = trackInfoList.stream().map(TrackInfo::getId).collect(Collectors.toList());
        List<Long> needPaidIdList = trackInfoAllList.stream().filter(needPaid -> !paidTrackList.contains(needPaid)).collect(Collectors.toList());
        // 构建返回结果
        List<Map<String, Object>> maplist = new ArrayList<>();
        if (needPaidIdList.size() >= 0) {
            // 显示本集
            HashMap<String, Object> map = new HashMap<>();
            map.put("name", "本集");
            map.put("price", price);
            map.put("trackCount", 0);
            maplist.add(map);
        }
        if (needPaidIdList.size() > 0 && needPaidIdList.size() <= 10) {
            // size ∈ (0,10)
            HashMap<String, Object> map = new HashMap<>();
            map.put("name", "买" + needPaidIdList.size() + "集");
            map.put("price", price.multiply(new BigDecimal(String.valueOf(needPaidIdList.size()))));
            map.put("trackCount", needPaidIdList.size());
            maplist.add(map);
        }
        if (needPaidIdList.size() > 10) {
            // 超过十集，显示十集
            HashMap<String, Object> map = new HashMap<>();
            map.put("name", "买10集");
            map.put("price", price.multiply(new BigDecimal("10")));
            map.put("trackCount", 10);
            maplist.add(map);
        }
        if (needPaidIdList.size() > 30) {
            HashMap<String, Object> map = new HashMap<>();
            map.put("name", "买30集");
            map.put("price", price.multiply(new BigDecimal("30")));
            map.put("trackCount", 30);
            maplist.add(map);
        }
        return maplist;
    }

    @Override
    public List<TrackInfo> findPaidTrackInfoList(Long trackId, Integer trackCount) {
        List<TrackInfo> trackInfoList = new ArrayList<>();
        // 获取当前声音对象
        TrackInfo trackInfo = this.getById(trackId);
        // 获取用户已购买过的声音列表 (有可能是空，也有可能不是)
        Result<List<Long>> userPaidTrackListResult = userInfoFeignClient.findUserPaidTrackList(trackInfo.getAlbumId());
        Assert.notNull(userPaidTrackListResult, "用户已购买过声音结果集为空");
        List<Long> userPaidTrackList = userPaidTrackListResult.getData();
        // 获取从当前声音开始，往后数 n条记录
        if (trackCount > 0) {
            if (!CollectionUtils.isEmpty(userPaidTrackList)) {
                // 有购买记录
                trackInfoMapper.selectList(new LambdaQueryWrapper<TrackInfo>()
                        .eq(TrackInfo::getAlbumId, trackInfo.getAlbumId())
                        .gt(TrackInfo::getOrderNum, trackInfo.getOrderNum())
                        .notIn(TrackInfo::getId, userPaidTrackList)
                        .eq(TrackInfo::getIsDeleted, 0)
                        .last("limit " + trackCount));
            } else {
                trackInfoMapper.selectList(new LambdaQueryWrapper<TrackInfo>()
                        .eq(TrackInfo::getAlbumId, trackInfo.getAlbumId())
                        .gt(TrackInfo::getOrderNum, trackInfo.getOrderNum())
                        .eq(TrackInfo::getIsDeleted, 0)
                        .last("limit " + trackCount));
            }
        } else {
            // 购买本集
            trackInfoList.add(trackInfo);
        }
        return trackInfoList;
    }

    /**
     * 保存声音统计数据
     *
     * @param trackId
     * @param statPlay
     */
    private void saveTrackStat(Long trackId, String statPlay) {
        // 创建对象
        TrackStat trackStat = new TrackStat();
        trackStat.setTrackId(trackId);
        trackStat.setStatType(statPlay);
        trackStat.setStatNum(new Random().nextInt(10000));
        trackStatMapper.insert(trackStat);
    }
}
